package jp.tkym.labs.store.api;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class EntityConfigProvider{
	private static final EntityConfigProvider singleton = new EntityConfigProvider();
	private Map<Class<?>, EntityConfig> map;
	
	private EntityConfigProvider(){
		map = new ConcurrentHashMap<Class<?>, EntityConfig>();
	}
	
	public static EntityConfigProvider getInstance(){
		return singleton;
	}
	
	public <T> EntityConfig get(Class<T> cls){
		EntityConfig config = map.get(cls);
		if(config == null){
			config = interpreter(cls);
			map.put(cls, config);
		} 
		return config;
	}
	
	<T> EntityConfig interpreter(Class<T> cls){
		Entity entity = cls.getAnnotation(Entity.class);
		if(entity == null) return null;
		
		EntityConfig config = new EntityConfig();
		
		Parent parent = cls.getAnnotation(Parent.class); 
		if(parent != null) config.setParent(parent.value());
		
		for(Method m : cls.getMethods()){
			if(m.getAnnotation(Key.class) != null)
				config.setKeyProperty(getterPropertyName(m));
			if(m.getAnnotation(Indexed.class) != null)
				config.addIndexedProperty(getterPropertyName(m));
		}
		return config;
	}
	
	private static final String GET = "get";
	private static final String GET_CLASS = "getClass";
	private static final String IS  = "is";
	
	private String getterPropertyName(Method method){
		String methodName = method.getName();
		if(methodName.startsWith(GET) && methodName.length()>3 && !methodName.equals(GET_CLASS))
			return propertyName(3, methodName);
		if(methodName.startsWith(IS) && methodName.length()>2 && method.getReturnType().equals(boolean.class))
			return propertyName(2, methodName);
		return null;
	}
	
	private String propertyName(int length, String methodName){
		char[] charArray = methodName.substring(length).toCharArray();
		charArray[0] = Character.toLowerCase(charArray[0]);
		return new String(charArray);
	}
	
	public class EntityConfig{
		private Class<?> parent;
//		private String idProperty;
		private String keyProperty;
		private HashSet<String> indexedProperty = new HashSet<String>();
		
		public Class<?> getParent() {
			return parent;
		}
		void setParent(Class<?> parent) {
			this.parent = parent;
		}
//		public String getIdProperty() {
//			return idProperty;
//		}
//		void setIdProperty(String idProperty) {
//			this.idProperty = idProperty;
//		}
		public String getKeyProperty() {
			return keyProperty;
		}
		void setKeyProperty(String nameProperty) {
			this.keyProperty = nameProperty;
		}
		void addIndexedProperty(String property){
			this.indexedProperty.add(property);
		}
		public boolean isIndexedProperty(String property){
			return indexedProperty.contains(property);
		}
		public Set<String> indexedProperties(){
			return indexedProperty;
		}
	}
}